import { useGetDefaultFilterValue } from './Filter/hook';
import { getFrequencyPoints } from 'common/utils/eq-filter/utils';
import { FilterOptionsWithId } from 'common/utils/eq-filter/types';
import { useThrottle } from 'ahooks';
import { isNil } from 'lodash';
import { memo, useEffect, useMemo, useRef } from 'react';
import type { FiltersValue } from './types';
import { Point } from './types';
import {
  linearInterpolationValue,
  linearTransform,
  logTransform,
  useGraph,
} from './useGraph';

interface ChartProps {
  value: NonNullable<FiltersValue>;
  onAddFilter: (addValue?: Omit<FilterOptionsWithId, 'id'>) => void;
  onFilterChange: (eq: FilterOptionsWithId, id: string) => void;
  onSelectFilter: (id: string) => void;
  readOnly?: boolean;
  onGraphPointsChange?: (graphPoints: {x:number;y:number}[])=>void;
}

const graphConfig = {
  width: 1200,
  height: 600,
  margin: {
    top: 40,
    right: 40,
    bottom: 40,
    left: 65,
  },
  xMin: 20.0,
  xMax: 20000.0,
  yMin: 60,
  yMax: 130,
  isDarkMode: false,
  xLabelSign: false,
  xLabelSuffix: 'Hz',
  yInterval: 10,
  yLabelSuffix: 'dB',
  yLabelSign: true,
  xTransform: logTransform,
  yTransform: linearTransform,
  tooltip: {
    enabled: true,
  },
  interaction: {
    snapToXLine: true,
    snapThreshold: (x: number) => Math.max(1, 6 ** (Math.log10(x) - 1)),
  },
  frequencyBands: [],
};

function Chart(props: ChartProps) {
  const { value, onAddFilter, onFilterChange, onSelectFilter, readOnly, onGraphPointsChange } = props;
  const defaultFilterValue = useGetDefaultFilterValue();

  const { eqs, freqToDB, project = {} } = value;

  const throttleEqs = useThrottle(eqs || [], { wait: 30 });

  const canvasRef = useRef<HTMLCanvasElement>(null);
  const graphConfigRef = useRef({ ...graphConfig, ...project });
  const selectedPointIdRef = useRef<string | undefined>(undefined);

  // 频响原始数据
  const headphonesPoints = useMemo(() => {
    // // 转换频响数据
    const sourceData = freqToDB.dataSet || [];
    const freqToDBData: Point[] = [];

    for (let j = 1; j < sourceData.length; j++) {
      const item = sourceData[j];
      if (item && item.length > 1) {
        freqToDBData.push({
          x: Number(item[0]),
          y: Number(item[1]),
        });
      }
    }
    return freqToDBData;
  }, [freqToDB]);

  // 计算均衡器后的频响数据
  const graphPoints = useMemo(() => {
    return getFrequencyPoints(headphonesPoints, throttleEqs);
  }, [headphonesPoints, throttleEqs]);

  useEffect(()=>{
    onGraphPointsChange?.(graphPoints)
  },[graphPoints])


  // 均衡器点
  const highlightPoints = useMemo(() => {
    return throttleEqs.map((item) => {
      let i = 0,
        j = graphPoints.length - 1;

      while (i <= j) {
        const mid = (i + j) >> 1;
        if (graphPoints[mid].x === item.frequency) {
          return {
            x: item.frequency,
            y: graphPoints[mid].y,
          };
        }
        if (graphPoints[mid].x < item.frequency) {
          i = mid + 1;
        } else {
          j = mid - 1;
        }
      }

      return {
        x: item.frequency,
        y: linearInterpolationValue(
          graphPoints[i],
          graphPoints[j],
          item.frequency,
        ),
      };
    });
  }, [throttleEqs, graphPoints]);

  const selectedPoint = useMemo(() => {
    if (isNil(value)) {
      return;
    }

    const eq = value.eqs.find((e) => e.id === value.currentEQId);
    if (!eq) {
      return undefined;
    }

    return highlightPoints.find((i) => i.x === eq.frequency);
  }, [highlightPoints, value]);

  useGraph({
    canvasRef: canvasRef,
    graphPoints,
    graphHighlightPoints: highlightPoints,
    graphConfig: graphConfigRef.current,
    selectedPoint,

    addPoint(point) {
      if(readOnly){
        return;
      }
      onAddFilter?.({
        ...defaultFilterValue,
        frequency: point.x,
      });
    },

    onClick(point) {
      if (!value) {
        return;
      }
      const id = eqs.find((e) => e.frequency === point.x)?.id;
      if(!id){
        return;
      }
      selectedPointIdRef.current = id;
      onSelectFilter(id);
    },

    onDragging(point) {
      if(readOnly){
        return;
      }
      if (selectedPointIdRef.current === undefined || !value) {
        return;
      }

      const eq = eqs.find((e) => e.id === selectedPointIdRef.current);
      if (!eq) {
        return;
      }

      onFilterChange(
        {
          ...eq,
          frequency: point.x,
        },
        selectedPointIdRef.current,
      );
    },

    onUpdateSize(width, height) {
      graphConfigRef.current = {
        ...graphConfigRef.current,
        width,
        height,
      };
    },
  });

  return (
    <div
      style={{
        backgroundColor: 'rgba(246,235,235,0.3)',
        height: 600,
      }}
    >
      <canvas
        ref={canvasRef}
        style={{ width: '100%', height: '100%' }}
      ></canvas>
    </div>
  );
}

export default memo(Chart);
